package com.quyunshuo.module.home.activity.time

import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ObjectAnimator
import android.content.Context
import android.content.res.Resources
import android.graphics.Camera
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Matrix
import android.graphics.Paint
import android.graphics.Rect
import android.graphics.Typeface
import android.graphics.drawable.Drawable
import android.util.AttributeSet
import android.view.View
import androidx.annotation.Keep
import androidx.core.content.res.ResourcesCompat
import com.quyunshuo.module.home.R
import kotlin.math.roundToInt

import android.util.TypedValue


/**
 * 翻页数字视图
 *
 * 功能：
 * 1. 实现数字翻页动画效果
 * 2. 支持自定义文本大小、颜色、字体
 * 3. 支持自定义动画时长
 * 4. 提供顶部和底部背景绘制
 *
 * 使用方式：
 * 在XML布局中添加：
 * <com.quyunshuo.module.home.activity.time.FlipTextView
 *     android:layout_width="wrap_content"
 *     android:layout_height="wrap_content"
 *     app:flip_text="00"
 *     app:flip_textSize="24sp"
 *     app:flip_textColor="#FFFFFF"
 *     app:flip_animationDuration="300"/>
 */
class FlipTextView @JvmOverloads constructor(
    context: Context,          // 上下文对象
    attrs: AttributeSet? = null, // XML属性集
    defStyleAttr: Int = 0       // 默认样式属性
) : View(context, attrs, defStyleAttr),
    ResourceHelper {           // 实现资源帮助接口

    // 相机对象，用于实现3D翻转效果
    private val camera = Camera()
    // 相机变换矩阵
    private val cameraMatrix = Matrix()

    // 资源对象访问器
    override val res: Resources
        get() = resources

    // 文本颜色属性（带重绘）
    var textColor: Int
        get() = textPaint.color
        set(value) {
            textPaint.color = value
            invalidate() // 颜色变化时重绘
        }

    // 文本大小属性（带重绘）
    var textSize: Float
        get() = textPaint.textSize
        set(value) {
            textPaint.textSize = value
            invalidate() // 大小变化时重绘
        }

    // 字体属性（带重绘）
    var typeface: Typeface
        get() = textPaint.typeface
        set(value) {
            textPaint.typeface = value
            invalidate() // 字体变化时重绘
        }

    // 文本绘制画笔
    private val textPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        color = Color.GRAY // 默认灰色
    }

    // 分隔线宽度（转换为dp）
    private val dividerWidth = 0f.dp

    // 顶部背景（翻页的上半部分）
    private val topBackground: Drawable =
        ResourcesCompat.getDrawable(resources, R.drawable.bg_flip_top, null)!!

    // 底部背景（翻页的下半部分）
    private val bottomBackground: Drawable =
        ResourcesCompat.getDrawable(resources, R.drawable.bg_flip_bottom, null)!!

    // 当前显示的文本
    private var currentText: String = ""
    // 下一个要显示的文本
    private var nextText: String = ""

    // 文本属性（带动画效果）
    var text: String
        get() = currentText
        set(value) {
            // 如果当前文本不为空，则启动翻页动画
            if (currentText != "") {
                nextText = value
                startFipAnimation()
            } else {
                // 首次设置文本，直接显示
                currentText = value
                invalidate()
            }
        }

    /**
     * 启动翻页动画
     */
    private fun startFipAnimation() {
        // 设计模式下不执行动画
        if (isInEditMode) {
            return
        }

        // 如果动画正在运行，先取消
        if (flipAnimator.isRunning) {
            flipAnimator.cancel()
        }

        // 启动动画
        flipAnimator.start()
    }

    // 当前翻转角度（0-360度）
    @get:Keep
    @set:Keep
    var degrees: Float = 0f
        set(value) {
            field = value % 360f // 确保角度在0-360度范围内
            invalidate() // 角度变化时重绘
        }

    // 动画时长（毫秒）
    var animationDuration = 200L
        set(value) {
            field = value
            initAnimator() // 更新动画时长时重新初始化动画器
        }

    // 翻转动画器
    private lateinit var flipAnimator: Animator

    init {
        // 初始化文本大小
        textSize = 30.sp

        // 初始化动画器
        initAnimator()

        // 设计模式下设置默认文本
        if (isInEditMode && currentText == "") {
            currentText = "59"
        }

        // 解析XML属性
        parseAttrs(attrs, defStyleAttr)
    }

    /**
     * 初始化动画器
     */
    private fun initAnimator() {
        // 创建属性动画：从0度到180度
        flipAnimator = ObjectAnimator.ofFloat(this, "degrees", 0f, 180f)
            .apply {
                // 添加动画结束监听器
                addListener(object : AnimatorListenerAdapter() {
                    override fun onAnimationEnd(animation: Animator) {
                        super.onAnimationEnd(animation)
                        // 动画结束时更新当前文本
                        currentText = nextText
                        // 重置角度为0度
                        degrees = 0f
                    }
                })

                // 设置动画时长
                duration = animationDuration
            }
    }

    /**
     * 解析XML属性
     */
    private fun parseAttrs(attrs: AttributeSet?, defStyleAttr: Int) {
        if (attrs == null) {
            return
        }

        context.theme.obtainStyledAttributes(
            attrs,
            R.styleable.FlipTextView,
            defStyleAttr,
            0
        ).apply {
            try {
                // 获取文本属性
                currentText = getString(R.styleable.FlipTextView_flip_text) ?: ""

                // 获取文本大小
                textSize = getDimension(R.styleable.FlipTextView_flip_textSize, 30.sp)

                // 获取文本颜色
                textColor = getColor(R.styleable.FlipTextView_flip_textColor, Color.WHITE)

                // 获取动画时长
                animationDuration =
                    getInt(R.styleable.FlipTextView_flip_animationDuration, 200).toLong()

                // 获取自定义字体
                val fontId = getResourceId(R.styleable.FlipTextView_flip_textFont, -1)
                if (fontId != -1 && !isInEditMode) {
                    textPaint.typeface = ResourcesCompat.getFont(context, fontId)
                }
            } finally {
                // 回收资源
                recycle()
            }
        }
    }

    /**
     * 测量视图尺寸
     */
    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        // 计算期望高度（基于文本大小）
        val desiredHeight = Math.max(suggestedMinimumHeight, (textSize / 0.55f).roundToInt())

        // 计算期望宽度
        var desiredWidth = suggestedMinimumWidth
        if (currentText.isNotEmpty()) {
            // 计算文本宽度（考虑内边距）
            var textAndPaddingWidth = Math.max(
                textPaint.measureText(currentText).roundToInt(),
                desiredHeight
            )
            textAndPaddingWidth += paddingLeft + paddingRight

            desiredWidth = Math.max(textAndPaddingWidth, desiredWidth)
        }

        // 根据测量规格计算最终尺寸
        val width = getMeasuredSize(desiredWidth, widthMeasureSpec)
        val height = getMeasuredSize(desiredHeight, heightMeasureSpec)

        // 设置测量尺寸
        setMeasuredDimension(width, height)
    }

    /**
     * 根据测量规格计算尺寸
     *
     * @param desired 期望尺寸
     * @param measureSpec 测量规格
     * @return 最终尺寸
     */
    private fun getMeasuredSize(desired: Int, measureSpec: Int): Int {
        val mode = MeasureSpec.getMode(measureSpec)
        val size = MeasureSpec.getSize(measureSpec)

        return when (mode) {
            MeasureSpec.EXACTLY -> size // 精确模式：使用指定尺寸
            MeasureSpec.AT_MOST -> Math.min(size, desired) // AT_MOST模式：取较小值
            else -> desired // 未指定模式：使用期望尺寸
        }
    }

    /**
     * 绘制视图
     */
    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)

        // 安全检查
        if (canvas == null) {
            return
        }

        // 绘制下一个文本的上半部分（始终在底部）
        if (degrees > 0f) drawTopSide(canvas, 0f, nextText)

        // 如果当前文本的上半部分仍然可见（翻转角度小于90度）
        if (degrees < 90) drawTopSide(canvas, -degrees, currentText)

        // 如果当前文本的下半部分仍然可见（翻转角度小于180度）
        if (degrees < 180f) drawBottomSide(canvas, 0f, currentText)

        // 如果下一个文本的下半部分可见（翻转角度大于等于90度）
        if (degrees >= 90) drawBottomSide(canvas, 180f - degrees, nextText)
    }

    /**
     * 视图从窗口分离时调用
     */
    override fun onDetachedFromWindow() {
        // 如果动画正在运行，先取消
        if (flipAnimator.isRunning) {
            flipAnimator.cancel()
        }
        super.onDetachedFromWindow()
    }

    /**
     * 绘制上半部分（顶部）
     *
     * @param canvas 画布
     * @param rotation 旋转角度
     * @param text 要绘制的文本
     */
    private fun drawTopSide(canvas: Canvas, rotation: Float, text: String) {
        drawTextSide(canvas, rotation, text, -1f)
    }

    /**
     * 绘制下半部分（底部）
     *
     * @param canvas 画布
     * @param rotation 旋转角度
     * @param text 要绘制的文本
     */
    private fun drawBottomSide(canvas: Canvas, rotation: Float, text: String) {
        drawTextSide(canvas, rotation, text, 1f)
    }

    /**
     * 绘制文本面（通用方法）
     *
     * @param canvas 画布
     * @param rotation 旋转角度
     * @param text 要绘制的文本
     * @param sideMultiplier 面方向乘数（-1为上半部分，1为下半部分）
     */
    private fun drawTextSide(canvas: Canvas, rotation: Float, text: String, sideMultiplier: Float) {
        // 保存画布状态
        val checkPoint = canvas.save()

        // 计算区域尺寸
        val regionWidth = 1f * width
        val regionHeight = height / 2f - dividerWidth / 2f

        // 根据面方向调整位置
        if (sideMultiplier > 0f) {
            canvas.translate(0f, regionHeight + dividerWidth / 2f)
        }

        // 设置裁剪区域
        canvas.clipRect(0f, 0f, regionWidth, regionHeight)

        // 应用相机变换
        camera.save()
        camera.rotateX(rotation) // 绕X轴旋转
        camera.getMatrix(cameraMatrix)

        // 调整变换矩阵
        cameraMatrix.preTranslate(-regionWidth / 2f, sideMultiplier * regionHeight)
        cameraMatrix.postTranslate(regionWidth / 2f, -sideMultiplier * regionHeight)

        // 应用变换矩阵到画布
        canvas.concat(cameraMatrix)

        // 测量文本边界
        val textBounds = Rect()
        textPaint.getTextBounds(text, 0, text.length, textBounds)
        textPaint.isFakeBoldText = true // 字体加粗

        // 计算文本垂直位置
        val dyTop = height / 2f + textBounds.height() / 2f
        val dyBottom = dyTop - regionHeight - dividerWidth / 2f
        val dy = if (sideMultiplier < 0f) dyTop else dyBottom

        // 计算文本水平位置（居中）
        var dx =
            paddingLeft * 1f + (width - paddingLeft - paddingRight) / 2f - textBounds.width() / 2
        if (dx < 0) dx = 0f

        // 绘制背景
        val background = if (sideMultiplier < 0f) topBackground else bottomBackground
        val drawableWidth = (regionWidth - (paddingLeft + paddingRight)).roundToInt()
        var drawableHeight = regionHeight.toInt()

        // 调整背景位置
        val drawableTranslateY = if (sideMultiplier == -1f) {
            drawableHeight -= paddingTop
            paddingTop.toFloat()
        } else {
            drawableHeight -= paddingBottom
            0f
        }

        // 绘制背景
        canvas.save()
        canvas.translate(paddingLeft.toFloat(), drawableTranslateY)
        background.setBounds(0, 0, drawableWidth, drawableHeight)
        background.draw(canvas)
        canvas.restore()

        // 绘制文本
        canvas.drawText(text, dx, dy, textPaint)

        // 恢复相机状态
        camera.restore()

        // 恢复画布状态
        canvas.restoreToCount(checkPoint)
    }
}

/**
 * 扩展函数：将数值转换为dp单位
 */
val Number.dp: Float
    get() = TypedValue.applyDimension(
        TypedValue.COMPLEX_UNIT_DIP,
        this.toFloat(),
        Resources.getSystem().displayMetrics
    )